common-audit 字段审计使用

什么是字段审计

在后台开发中,一般的业务表都会包含一些审计记录的字段,例如创建人、创建时间、修改人和修改时间等。这些字段只是记录当时的操作人和操作时间,没有特别的逻辑。

对于个别敏感字段,需要记录其变更前后的数据值。比如,如果修改前是 A,修改后是 B,则需要将这些操作记录到数据库中,以便日后进行审计。

添加依赖

<!-- 字段审计 -->
<dependency>
    <groupId>com.pig4cloud</groupId>
    <artifactId>pigx-common-audit</artifactId>
</dependency>

实体字段标记审计

在需要审计的字段上添加 @DiffInclude@PropertyName 注解:

public class SysUser implements Serializable {
	@DiffInclude
	@PropertyName("手机号")
	private String phone;
}
注解说明

@DiffInclude 标记字段需要审计,@PropertyName 指定字段的显示名称

业务层添加审计

在需要审计的业务方法上添加 @Audit 注解:

public Boolean updateUser(UserDTO userDto) {
    // 业务逻辑
    return Boolean.TRUE;
}

在上述业务层中,userDto 是前端更新后的数据。如果要进行审计,需要获取原有数据。

方法一: 使用 Spring SpEL 表达式(推荐)

@Audit(name = "用户更新", spel = "@sysUserMapper.selectById(#userDto.userId)")

表达式解析:

  • @sysUserMapper: 获取名称为 sysUserMapper 的 Bean
  • selectById: 调用 selectById 方法
  • #userDto.userId: 方法参数来自于当前方法(service.updateUser)的 userDto 的 userId 字段

方法二: 直接指定原值(写死)

@Audit(name = "用户更新", oldVal = "17034642449")
方法二局限性

直接写死原值不够灵活,仅适用于特殊测试场景,生产环境建议使用 SpEL 表达式

@Audit 注解属性说明

属性解释
name审计项名称
value / spel表达式语言,用于生成审计信息
oldVal修改前的值(覆盖 spel 的结果)
newVal修改后的值(覆盖 service 方法的执行结果)

常见问题

为什么我自己的方法不记录

audit 基于 Spring AOP,请务必明确知悉 Spring AOP 的触发条件,尤其需要注意同类内部方法调用(方法嵌套)不会触发代理,否则将导致 AOP 失效,进而使审计逻辑无法生效。

AOP 生效条件示例

// 业务类
class Service {

    @Audit
    methodA() {
        // AOP 生效
        doSomething()
    }

    methodB() {
        // 同类内部调用
        // 不经过代理,AOP 不生效
        methodA()
    }
}

// 正确调用方式
class Controller {

    Service service

    call() {
        // 通过 Spring 容器代理调用
        // AOP 生效
        service.methodA()
    }
}
最佳实践

审计方法应该由外部调用者(如 Controller)直接调用,避免在同一个类内部进行方法嵌套调用